import { Injectable, Inject } from "@nestjs/common";

import * as Client from "ali-oss";
import * as dayjs from "dayjs";
import { ConfigType } from "@nestjs/config";
import ossConfig from "../../config/oss.config";
import OSS from "ali-oss";
import * as $OpenApi from "@alicloud/openapi-client";
import ocr_api20210707, * as $ocr_api20210707 from "@alicloud/ocr-api20210707";
import Util, * as $Util from "@alicloud/tea-util";

@Injectable()
export class OssService {
  private client: any;
  private config: Record<string, any>;
  private staticClient: any;
  private staticConfig: Record<string, any>;
  // ocr身份证识别
  private ORCClient: ocr_api20210707;
  private OCRConfig: Record<string, any>;

  constructor(
    @Inject(ossConfig.KEY)
    private readonly ossConf: ConfigType<typeof ossConfig>
  ) {
    this.config = {
      region: ossConf.region,
      accessKeyId: ossConf.accessKeyId,
      accessKeySecret: ossConf.accessKeySecret,
      secure: true,
      // 存储桶名字
      bucket: ossConf.bucket,
      // 文件存储路径
      // dir: 'cad/',
      // 设置上传回调URL，即回调服务器地址，用于处理应用服务器与OSS之间的通信。
      // OSS会在文件上传完成后，把文件上传信息通过此回调URL发送给应用服务器。
      // 例如callbackUrl填写为https oss-demo.aliyuncs.com:23450。
      callbackUrl: "http://localhost:3000/oss/result",
    };
    this.client = new Client(<OSS.Options>this.config);
    this.staticConfig = {
      region: "oss-cn-qingdao",
      accessKeyId: ossConf.accessKeyId,
      accessKeySecret: ossConf.accessKeySecret,
      // 存储桶名字
      bucket: "staticolgstorage",
      // 文件存储路径
      // dir: 'cad/',
      // 设置上传回调URL，即回调服务器地址，用于处理应用服务器与OSS之间的通信。
      // OSS会在文件上传完成后，把文件上传信息通过此回调URL发送给应用服务器。
      // 例如callbackUrl填写为https oss-demo.aliyuncs.com:23450。
      callbackUrl: "http://localhost:3000/oss/result",
    };
    this.staticClient = new Client(<OSS.Options>this.staticConfig);
    this.OCRConfig = new $OpenApi.Config({
      accessKeyId: ossConf.accessKeyId,
      accessKeySecret: ossConf.accessKeySecret,
    });
    this.OCRConfig.endpoint = ossConf.endpoint;
    this.ORCClient = new ocr_api20210707(<any>this.OCRConfig);
  }

  //  定义两个存储桶连接
  //  想清楚
  async getSignature() {
    // const client = new Client(config);

    const date = new Date();
    // 时长加 1 天，作为签名的有限期
    date.setDate(date.getDate() + 1);

    const policy = {
      // 设置签名的有效期，格式为Unix时间戳
      expiration: date.toISOString(),
      conditions: [
        ["content-length-range", 0, 10485760000], // 设置上传文件的大小限制
      ],
    };

    // 生成签名，策略等信息
    const formData = await this.client.calculatePostSignature(policy);

    // bucket域名，客户端将向此地址发送请求
    const location = await this.client.getBucketLocation("kaowustorage");
    const host = `https://${this.config.bucket}.${location.location}.aliyuncs.com`;

    // 上传回调。
    const callback = {
      // 设置回调请求的服务器地址
      callbackUrl: this.config.callbackUrl,
      // 设置回调的内容，${object} 等占位符会由 OSS 进行填充
      // ${object}表示文件的存储路径，${mimeType}表示资源类型，对于图片类型的文件，可以通过${imageInfo.height}等去设置宽高信息
      callbackBody:
        "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
      // 设置回调的内容类型，也支持 application/json
      callbackBodyType: "application/x-www-form-urlencoded",
    };

    // 响应给客户端的签名和策略等信息
    return {
      expire: dayjs().add(1, "days").unix().toString(),
      policy: formData.policy,
      signature: formData.Signature,
      accessId: formData.OSSAccessKeyId,
      host,
      dir: this.config.dir,
      // 传给客户端的回调参数，需要通过Buffer.from 对 JSON 进行 Base64 编码
      callback: Buffer.from(JSON.stringify(callback)).toString("base64"),
    };
  }

  async getstaticSignature() {
    // const client = new Client(config);

    const date = new Date();
    // 时长加 1 天，作为签名的有限期
    date.setDate(date.getDate() + 1);

    const policy = {
      // 设置签名的有效期，格式为Unix时间戳
      expiration: date.toISOString(),
      conditions: [
        ["content-length-range", 0, 10485760000], // 设置上传文件的大小限制
      ],
    };

    // 生成签名，策略等信息
    const formData = await this.staticClient.calculatePostSignature(policy);

    // bucket域名，客户端将向此地址发送请求
    const location = await this.staticClient.getBucketLocation("staticolgstorage");
    const host = `https://${this.staticConfig.bucket}.${location.location}.aliyuncs.com`;

    // 上传回调。
    const callback = {
      // 设置回调请求的服务器地址
      callbackUrl: this.staticConfig.callbackUrl,
      // 设置回调的内容，${object} 等占位符会由 OSS 进行填充
      // ${object}表示文件的存储路径，${mimeType}表示资源类型，对于图片类型的文件，可以通过${imageInfo.height}等去设置宽高信息
      callbackBody:
        "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
      // 设置回调的内容类型，也支持 application/json
      callbackBodyType: "application/x-www-form-urlencoded",
    };

    // 响应给客户端的签名和策略等信息
    return {
      expire: dayjs().add(1, "days").unix().toString(),
      policy: formData.policy,
      signature: formData.Signature,
      accessId: formData.OSSAccessKeyId,
      host,
      dir: this.staticConfig.dir,
      // 传给客户端的回调参数，需要通过Buffer.from 对 JSON 进行 Base64 编码
      callback: Buffer.from(JSON.stringify(callback)).toString("base64"),
    };
  }

  async generateSignedUrl(key: string): Promise<string> {
    const expire = Math.floor(Date.now() / 1000) + 3600; // 有效期为1小时
    // 构建下载 URL
    const downloadUrl = this.client.signatureUrl(key, {
      expires: expire,
    });

    return downloadUrl;
  }

  async getFileAsBlob(key: string): Promise<Buffer> {
    try {
      const result = await this.client.get(key);
      const buffer = await Buffer.from(result.content, "base64");
      return buffer;
    } catch (error) {
      throw new Error(`Error getting file: ${error.message}`);
    }
  }

  async getResult(xOssPubKeyUrl: string, file: any) {
    // 通过 Base64 解码公钥地址
    const pubKeyAddr = Buffer.from(xOssPubKeyUrl, "base64").toString("ascii");

    //  判断请求头中的 x-oss-pub-key-url 是否来源于OSS服务器
    if (!pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")) {
      // 如果不是来源于OSS服务器，则返回 “verify not ok”，表明回调失败
      return {
        status: "verify not ok",
      };
    }
    // 如果 x-oss-pub-key-url 来源于OSS服务器，则返回“Ok”和文件信息，表明回调成功
    return {
      status: "Ok",
      file,
    };
  }

  async ORC(url: string, type: string) {
    // 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
    // 工程代码泄露可能会导致 AccessKey 泄露，并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用，仅供参考，建议使用更安全的 STS 方式，更多鉴权访问方式请参见：https://help.aliyun.com/document_detail/378664.html
    // let client = this.ORCClient();
    // 需要安装额外的依赖库，直接点击下载完整工程即可看到所有依赖。
    // const bodyStream = Stream.readFromFilePath('<your-file-path>');
    const recognizeIdcardRequest = new $ocr_api20210707.RecognizeAllTextRequest({
      // body: bodyStream,
      // outputFigure: true,
      // outputQualityInfo: true,
      url: url,
      type,
      // 'https://lgstorage.oss-cn-qingdao.aliyuncs.com/apartment/houseType/712f9305-651d-4b01-ba57-d26d719960e0323488274767.jpeg?OSSAccessKeyId=LTAI5tR4nrrdyY274G3cnx8V&Expires=3407512152&Signature=jGHaW5duhNbW6i93TfRg4TyeOsA%3D',
    });
    const runtime = new $Util.RuntimeOptions({});
    try {
      // 复制代码运行请自行打印 API 的返回值 recognizeAllTextWithOptions
      const res = await this.ORCClient.recognizeAllTextWithOptions(recognizeIdcardRequest, runtime);

      return res?.body?.data;
    } catch (error) {
      // 错误 message
      Util.assertAsString(error.message);
      if (error.message.indexOf("illegalImageContent") !== -1) {
        return {
          data: JSON.stringify({
            code: 400,
            message: "非法图像内容,请上传正确图片",
          }),
        };
      }
    }
  }
}
